//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Utils/UI/UILocale.h"

namespace Engine
{
namespace Utils
{

	//
	// UI Localization
	//

	class UILocalization
	{
	// types
	private:
		typedef Ptr< UILocale >			UILocalePtr;
		typedef UILocale::StringID_t	StringID_t;

		struct Pack
		{
			UILocalePtr		locale;
			string			packName;
			uint			id;
			///
			Pack () : id(-1) {}
			Pack (UILocalePtr &l, uint id, uni_c_string name) : locale(l), id(id), packName(name) {}
		};

		typedef array< Pack >	locale_packs_t;


	// variables
	private:
		Ptr<UtilsCore>					_core;
		MetaData::UILocaleLanguageCfg	_settings;
		locale_packs_t					_localePacks;


	// metadata
	public:
		struct LocalePack
		{
			string_array_t	files;
			string			name;
			uint			id;
			///
			LocalePack () : id(0) {}
		};


	// methods
	public:
		UILocalization (Ptr<UtilsCore> core) : _core(core)
		{
			_settings.InitMetaData();
		}
		
		~UILocalization ()
		{
			Clear();
		}


		bool Load (uni_c_string path, uni_c_string settings, const array<LocalePack> &packs)
		{
			Clear();

			string				fname;
			static_obj_tree_t	cfg_tree;

			// load settings
			FileAddressUtils::BuildPath( fname, path, settings );
			
			cfg_tree.Push( TConfigObjInfo( _settings.GetMetaIterator(), null ) );
			
			CHECK_ERR( _core->Parse( fname, cfg_tree ) );


			// load locale files
			FOR( i, packs )
			{
				UILocalePtr	locale = new UILocale( _core );

				locale->Load( packs[i].id, path, packs[i].files );

				_localePacks.PushBack( Pack( locale, packs[i].id, packs[i].name ) );
			}

			return true;
		}


		bool Save (uni_c_string path, uni_c_string ext)
		{
			string	fname;

			FOR( i, _localePacks )
			{
				FileAddressUtils::BuildPath( fname, path, _settings.iso3Name );
				
				fname << '_' << _localePacks[i].packName << '.' << ext;

				CHECK_ERR( _localePacks[i].locale->Save( fname ) );
			}
			return true;
		}


		void Clear ()
		{
			FOR( i, _localePacks )
			{
				delete _localePacks[i].locale;
			}

			_localePacks.Clear();

			_settings = MetaData::UILocaleLanguageCfg();
		}


		bool Validate (const UILocalization * loc)
		{
			CHECK_ERR( _localePacks.Count() == loc->_localePacks.Count() );

			FOR( i, _localePacks )
			{
				CHECK_ERR( _localePacks[i].packName == loc->_localePacks[i].packName );
				CHECK_ERR( _localePacks[i].locale->Validate( loc->_localePacks[i].locale.ptr() ) );
			}
			return true;
		}


		void GetPacks (OUT map<uint, string> &packs) const
		{
			FOR( i, _localePacks )
			{
				packs.Add( _localePacks[i].id, _localePacks[i].packName );
			}
		}


		MetaData::UILocaleLanguageCfg const &	GetSettings () const
		{
			return _settings;
		}
		

		StringID_t GetStringId (uni_c_string str) const
		{
			FOR( i, _localePacks )
			{
				const StringID_t	id = _localePacks[i].locale->GetStringId( str );

				if ( id != 0 )
					return id;
			}
			return 0;
		}


		bool ChangeString (INOUT string &str) const
		{
			StringID_t	id = GetStringId( str );

			//ASSERT( id != 0 );

			str.ClearMem();
			str.Resize( sizeof(id), ' ', false );

			*(StringID_t *) str.ptr() = id;

			CHECK_ERR( str.Length() == sizeof(id) );

			return id != 0;
		}
	};



	//
	// UI All Localizations
	//

	class UIAllLocalizations
	{
	// types
	private:
		typedef AutoPtr< UILocalization >		UILocalizationPtr;
		typedef array< UILocalizationPtr >		localizations_t;
		typedef UILocalization::LocalePack		LocalePack;


	// variables
	private:
		Ptr<UtilsCore>		_core;
		localizations_t		_localizations;
		uint				_defaultLocale;
		string				_settingsName;


	// methods
	public:
		UIAllLocalizations (Ptr<UtilsCore> core) : _core(core), _defaultLocale(-1)
		{}

		
		bool Load (uni_c_string path, uni_c_string settings, uni_c_string defaultLoc, array<LocalePack> &packs)
		{
			_settingsName = FileAddressUtils::GetName( settings );


			FOR( i, packs )
			{
				uint &	id	= packs[i].id;
				bool	gen	= id == 0;

				if ( gen )
					id = 1;

				FOR( j, packs )
				{
					if ( i == j )
						continue;

					const uint	index = packs[j].id;

					if ( index == id )
					{
						if ( not gen )
						{
							// check unique index
							WARNING( "index is not unique, it will be changed!" );

							gen = true;
							id  = 1;
						}
						else
						{
							// generate unique index
							id++;
						}

						j = -1;
						continue;
					}
				}

				CHECK_ERR( id > 0 and id < 0xFFFF );
			}


			string			dir;
			string_array_t	dirs;

			CHECK_ERR( FileSystem::GetAllDirsInPath( path.cstr(), dirs ) );

			FOR( i, dirs )
			{
				if ( dirs[i] == "." or dirs[i] == ".." )
					continue;

				if ( dirs[i].Length() != 3 )
				{
					LOG( (string("Directory name \"") << dirs[i] << "\" is not ISO3 code.").cstr(), e_log_msg::WARNING_2 );
					continue;
				}

				FileAddressUtils::BuildPath( dir, path, dirs[i] );


				UILocalizationPtr	loc( new UILocalization( _core ) );

				CHECK_ERR( loc->Load( dir, settings, packs ) );

				_localizations.PushBack( loc );

				if ( _defaultLocale == -1 and defaultLoc == dirs[i] )
					_defaultLocale = _localizations.LastIndex();
			}


			// Validate
			CHECK_ERR( _defaultLocale < _localizations.Count() );

			UILocalization *	def = _localizations[ _defaultLocale ].ptr();

			FOR( i, _localizations )
			{
				if ( i == _defaultLocale )
					continue;

				CHECK_ERR( _localizations[i]->Validate( def ) );
			}

			return true;
		}


		bool Save (uni_c_string path, uni_c_string locExt, uni_c_string settingsExt)
		{
			// save locales
			FOR( i, _localizations )
			{
				CHECK_ERR( _localizations[i]->Save( path, locExt ) );
			}

			// save settings
			string	fname;
			FileAddressUtils::BuildPath( fname, path, _settingsName, settingsExt );

			CHECK_ERR( SaveSettings( fname ) );
			return true;
		}


		bool SaveSettings (uni_c_string filename)
		{
			// convert
			MetaData::UILocaleSettingsCfg	cfg;

			cfg.defaultLocale = _defaultLocale;
			cfg.languages.Resize( _localizations.Count(), false );

			FOR( i, _localizations ) {
				cfg.languages[i] = _localizations[i]->GetSettings();
			}

			GetDefaultLocale()->GetPacks( cfg.localePacks );
			CHECK_ERR( not cfg.localePacks.Empty() );


			// save
			WFilePtr	file;
			CHECK_ERR( (file = File::HddWFile::New( filename )).IsNotNull() );
		
			RESFILE_WRITE_HEADER( file, UILSettingsFileInfo );

			cfg.Serialize( file );

			return true;
		}


		UILocalization const * GetDefaultLocale () const
		{
			return _localizations[ _defaultLocale ].ptr();
		}
	};


}	// Utils
}	// Engine
